#define F_CPU 8000000UL		//8MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define sgA PB5			//defines segment A to PB5
#define sgB PB1			//defines segment B to PB1
#define sgC PD6			//defines segment C to PD6
#define sgD PB7			//defines segment D to PB7
#define sgE PB6			//defines segment E to PB6
#define sgF PB4			//defines segment F to PB4
#define sgG PD7			//defines segment G to PD7
#define DP PD5			//defines the decimal point to PD5
#define D2 PB3			//defines digit 2 on the display to PB3
#define D3 PB2			//defines digit 3 on the display to PB2
#define D4 PB0			//defines digit 4 on the display to PB0
#define BAUD_RATE 9600
#define	BAUD_PRESCALER (((F_CPU/(BAUD_RATE*16UL))) - 1 )
//Operating Mode: Asynchronous Normal mode for the UBRRn value

void USART_INIT(void)
//This function will set the micro controller for serial communication with the PC
//It sets the necessary baud rate registers, and prescaler value.
{
	UBRR0H = (uint8_t)(BAUD_PRESCALER >> 8);
	UBRR0L = (uint8_t)(BAUD_PRESCALER);
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	UCSR0C = (3 << UCSZ00);
}

unsigned char USART_RECEIVE(void)
//This function receives data from the PC terminal through the USB cable
{
	while(!(UCSR0A & (1<<RXC0)));
	return UDR0;
}

void USART_SEND(unsigned char data)
//Function to send data from the ATmega328P to the terminal on the PC
{
	while(!(UCSR0A & (1 << UDRE0)));
	UDR0 = data;
}

void zero(int seg) //Turn on segments AFEDCB
//This function sends a zero to the 7seg display
{
	PORTB = 0;
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgE)|(1<<sgD)|(1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void one(int seg) //Turn on segments BC
//This function sends a one to the 7seg display
{
	PORTB = 0;
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void two(int seg) //Turn on segments ABGED
//This function sends a two to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgE)|(1<<sgD);
	PORTD |= (1<<sgG);
	if(seg==D3) PORTD |= (1<<DP);
}

void three(int seg) //Turn on segments ABGCD
//This function sends a three to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgD);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void four(int seg) //Turn on segments FGBC
//This function sends a four to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgF)|(1<<sgB);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void five(int seg) //Turn on segments AFGCD
//This function sends a five to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgD);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void six(int seg) //Turn on segments AFGCDE
//This function sends a six to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgD)|(1<<sgE);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void seven(int seg) //Turn on segments ABC
//This function sends a seven to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void eight(int seg) //Turn on segments ABCDEFG
//This function sends an eight to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgD)|(1<<sgE)|(1<<sgF);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void nine(int seg) //Turn on segments AFGBC
//This function sends a nine to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgB);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void dpoint(int seg) //Turn on segments AFGBC
//This function sends a decimal point to the 7seg display
{
	PORTB = 0;	//reset ports
	PORTD = 0;
	PORTB |= (1<<seg);
	PORTB |= (1<<sgD)|(1<<sgF)|(1<<sgB);
	if(seg==D3) PORTD |= (1<<DP);
}

uint16_t ReadADC(uint8_t ADCchannel)
{
	ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);//select ADC channel with safety mask
	ADCSRA |= (1<<ADSC);						//single conversion mode
	while( ADCSRA & (1<<ADSC) );				//wait until ADC conversion is complete
	return ADC;
}

int main()
{
	// Set Ports B and D as outputs
	DDRB = 0xFF;
	DDRD = 0xFF;
	USART_INIT();							  //Call the USART initialization code
	ADMUX |= (1<<REFS0);					  //Select Vref=AVcc
	ADCSRA |= (1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);//set prescaller to 8 and enable ADC
	while(1)
	{
		int temp = ReadADC(0)*5; //Read ADC value, LM34 conversion: 10mV/1 degree Fahrenheit.
//This segment determines the farthest right digit, the hundreths place, DIGIT 4 on the 7seg********	
		int dig3 = temp;
		dig3=dig3%10;
		
		if(dig3==0) zero(D4);
		else if(dig3==1) one(D4);
		else if(dig3==2) two(D4);
		else if(dig3==3) three(D4);
		else if(dig3==4) four(D4);
		else if(dig3==5) five(D4);
		else if(dig3==6) six(D4);
		else if(dig3==7) seven(D4);
		else if(dig3==8) eight(D4);
		else if(dig3==9) nine(D4);
		else dpoint(D4);
//This segment determines the next digit, the tenths place, DIGIT 3 on the 7seg**********************
		int dig2 = temp/10;
		dig2 = dig2%10;
		
		if(dig2==0) zero(D3);
		else if(dig2==1) one(D3);
		else if(dig2==2) two(D3);
		else if(dig2==3) three(D3);
		else if(dig2==4) four(D3);
		else if(dig2==5) five(D3);
		else if(dig2==6) six(D3);
		else if(dig2==7) seven(D3);
		else if(dig2==8) eight(D3);
		else if(dig2==9) nine(D3);
		else dpoint(D3);
//This segment determines the digit left of the decimal, the ones place, DIGIT 2 on the 7seg*********
		int dig1 = temp/100;
		dig1 = dig1%10;
		
		if(dig1==0) zero(D2);
		else if(dig1==1) one(D2);
		else if(dig1==2) two(D2);
		else if(dig1==3) three(D2);
		else if(dig1==4) four(D2);
		else if(dig1==5) five(D2);
		else if(dig1==6) six(D2);
		else if(dig1==7) seven(D2);
		else if(dig1==8) eight(D2);
		else if(dig1==9) nine(D2);
		else dpoint(D2);
	}
	
}